home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / macros / texinfo / info / dir.c < prev    next >
C/C++ Source or Header  |  1994-01-28  |  7KB  |  225 lines

  1. /* dir.c -- How to build a special "dir" node from "localdir" files. */
  2.  
  3. /* This file is part of GNU Info, a program for reading online documentation
  4.    stored in Info format.
  5.  
  6.    Copyright (C) 1993 Free Software Foundation, Inc.
  7.  
  8.    This program is free software; you can redistribute it and/or modify
  9.    it under the terms of the GNU General Public License as published by
  10.    the Free Software Foundation; either version 2, or (at your option)
  11.    any later version.
  12.  
  13.    This program is distributed in the hope that it will be useful,
  14.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.    GNU General Public License for more details.
  17.  
  18.    You should have received a copy of the GNU General Public License
  19.    along with this program; if not, write to the Free Software
  20.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  
  22.    Written by Brian Fox (bfox@ai.mit.edu). */
  23.  
  24. #include <stdio.h>
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <sys/file.h>
  28. #include <sys/errno.h>
  29. #include "info-utils.h"
  30. #include "filesys.h"
  31. #include "tilde.h"
  32.  
  33. /* The "dir" node can be built from the contents of a file called "dir",
  34.    with the addition of the menus of every file called "localdir" found in
  35.    INFOPATH. */
  36.  
  37. static void add_menu_to_file_buffer (), insert_text_into_fb_at_binding ();
  38.  
  39. void
  40. maybe_build_dir_node (dirname, from_files_named)
  41.      char *dirname;
  42.      char *from_files_named;
  43. {
  44.   FILE_BUFFER *dir_buffer;
  45.  
  46.   /* See if the file has already been loaded and exists. */
  47.   dir_buffer = info_find_file (dirname);
  48.  
  49.   /* If there is no "dir" in the current info path, we cannot build one
  50.      from nothing. */
  51.   if (!dir_buffer)
  52.     return;
  53.  
  54.   /* If this directory has already been built, return now. */
  55.   if (dir_buffer->flags & N_CannotGC)
  56.     return;
  57.  
  58.   dir_buffer->flags |= N_CannotGC;
  59.  
  60.   /* For every file named FROM_FILES_NAMED in the search path, add the
  61.      contents of that file's menu to our "dir" node. */
  62.   {
  63.     struct stat finfo;
  64.     char *this_dir;
  65.     int namelen, path_index;
  66.     int update_tags = 0;
  67.  
  68.     namelen = strlen (from_files_named);
  69.     path_index = 0;
  70.  
  71.     /* Using each element of the path, check for "localdir".  Do not check
  72.        for "localdir.info.Z" or anything else.  Only files explictly named
  73.        "localdir" are eligible.  This is a design decision.  There can be
  74.        an info file name "localdir.info" which contains information on the
  75.        setting up of "localdir" files. */
  76.     while (this_dir = extract_colon_unit (infopath, &path_index))
  77.       {
  78.     char *fullpath;
  79.     int statable;
  80.  
  81.     /* Expand a leading tilde if one is present. */
  82.     if (*this_dir == '~')
  83.       {
  84.         char *tilde_expanded_dirname;
  85.  
  86.         tilde_expanded_dirname = tilde_expand_word (this_dir);
  87.         free (this_dir);
  88.         this_dir = tilde_expanded_dirname;
  89.       }
  90.  
  91.     fullpath = (char *)xmalloc (3 + strlen (this_dir) + namelen);
  92.     strcpy (fullpath, this_dir);
  93.     if (fullpath[strlen (fullpath) - 1] != '/')
  94.       strcat (fullpath, "/");
  95.     strcat (fullpath, from_files_named);
  96.  
  97.     statable = (stat (fullpath, &finfo) == 0);
  98.  
  99.     if (statable && S_ISREG (finfo.st_mode))
  100.       {
  101.         long filesize;
  102.         char *contents;
  103.  
  104.         contents = filesys_read_info_file (fullpath, &filesize, &finfo);
  105.  
  106.         if (contents)
  107.           {
  108.         update_tags++;
  109.         add_menu_to_file_buffer (contents, filesize, dir_buffer);
  110.         free (contents);
  111.           }
  112.       }
  113.  
  114.     free (fullpath);
  115.     free (this_dir);
  116.       }
  117.     if (update_tags)
  118.       build_tags_and_nodes (dir_buffer);
  119.   }
  120. }
  121.  
  122. /* Given CONTENTS and FB (a file buffer), add the menu found in CONTENTS
  123.    to the menu found in FB->contents.  Second argument SIZE is the total
  124.    size of CONTENTS. */
  125. static void
  126. add_menu_to_file_buffer (contents, size, fb)
  127.      char *contents;
  128.      long size;
  129.      FILE_BUFFER *fb;
  130. {
  131.   SEARCH_BINDING contents_binding, fb_binding;
  132.   long contents_offset, fb_offset;
  133.  
  134.   contents_binding.buffer = contents;
  135.   contents_binding.start = 0;
  136.   contents_binding.end = size;
  137.   contents_binding.flags = S_FoldCase | S_SkipDest;
  138.  
  139.   fb_binding.buffer = fb->contents;
  140.   fb_binding.start = 0;
  141.   fb_binding.end = fb->filesize;
  142.   fb_binding.flags = S_FoldCase | S_SkipDest;
  143.  
  144.   /* Move to the start of the menus in CONTENTS and FB. */
  145.   contents_offset = search_forward (INFO_MENU_LABEL, &contents_binding);
  146.   fb_offset = search_forward (INFO_MENU_LABEL, &fb_binding);
  147.  
  148.   /* If there is no menu in CONTENTS, quit now. */
  149.   if (contents_offset == -1)
  150.     return;
  151.  
  152.   /* If there is no menu in FB, make one. */
  153.   if (fb_offset == -1)
  154.     {
  155.       /* Find the start of the second node in this file buffer.  If there
  156.      is only one node, we will be adding the contents to the end of
  157.      this node. */
  158.       fb_offset = find_node_separator (&fb_binding);
  159.  
  160.       /* If not even a single node separator, give up. */
  161.       if (fb_offset == -1)
  162.     return;
  163.  
  164.       fb_binding.start = fb_offset;
  165.       fb_binding.start +=
  166.     skip_node_separator (fb_binding.buffer + fb_binding.start);
  167.  
  168.       /* Try to find the next node separator. */
  169.       fb_offset = find_node_separator (&fb_binding);
  170.  
  171.       /* If found one, consider that the start of the menu.  Otherwise, the
  172.      start of this menu is the end of the file buffer (i.e., fb->size). */
  173.       if (fb_offset != -1)
  174.     fb_binding.start = fb_offset;
  175.       else
  176.     fb_binding.start = fb_binding.end;
  177.  
  178.       insert_text_into_fb_at_binding
  179.     (fb, &fb_binding, INFO_MENU_LABEL, strlen (INFO_MENU_LABEL));
  180.  
  181.       fb_binding.buffer = fb->contents;
  182.       fb_binding.start = 0;
  183.       fb_binding.end = fb->filesize;
  184.       fb_offset = search_forward (INFO_MENU_LABEL, &fb_binding);
  185.       if (fb_offset == -1)
  186.     abort ();
  187.     }
  188.  
  189.   /* CONTENTS_OFFSET and FB_OFFSET point to the starts of the menus that
  190.      appear in their respective buffers.  Add the remainder of CONTENTS
  191.      to the end of FB's menu. */
  192.   fb_binding.start = fb_offset;
  193.   fb_offset = find_node_separator (&fb_binding);
  194.   if (fb_offset != -1)
  195.     fb_binding.start = fb_offset;
  196.   else
  197.     fb_binding.start = fb_binding.end;
  198.  
  199.   insert_text_into_fb_at_binding
  200.     (fb, &fb_binding, contents + contents_offset, size - contents_offset);
  201. }
  202.  
  203. static void
  204. insert_text_into_fb_at_binding (fb, binding, text, textlen)
  205.      FILE_BUFFER *fb;
  206.      SEARCH_BINDING *binding;
  207.      char *text;
  208.      int textlen;
  209. {
  210.   char *contents;
  211.   long start, end;
  212.  
  213.   start = binding->start;
  214.   end = fb->filesize;
  215.  
  216.   contents = (char *)xmalloc (fb->filesize + textlen + 1);
  217.   memcpy (contents, fb->contents, start);
  218.   memcpy (contents + start, text, textlen);
  219.   memcpy (contents + start + textlen, fb->contents + start, end - start);
  220.   free (fb->contents);
  221.   fb->contents = contents;
  222.   fb->filesize += textlen;
  223.   fb->finfo.st_size = fb->filesize;
  224. }
  225.